rm(list = ls())
library("rstudioapi")
setwd(dirname(getActiveDocumentContext()$path))

Uncomment and run this block if you haven’t had these packages installed

# install.packages("ona", repos = c("https://epistemic-analytics.gitlab.io/qe-packages/ona/cran/", "https://cran.rstudio.org"))
# install.packages("tma", repos = c("https://epistemic-analytics.gitlab.io/qe-packages/tma/cran/", "https://cran.rstudio.org"))
# install.packages("magrittr")

0. setting up constant variables (change as appropriate)

mapid = "57718789"
wd = paste0(getwd(), "/data/")

0. read A B C matrices and other relevant data

A_matrix = read_csv(paste0(wd, mapid, "_a_matrix.csv"))
B_matrix = read_csv(paste0(wd, mapid, "_b_matrix.csv"))
C_matrix = read.csv(paste0(wd, mapid, "_c_matrix.csv"))
sh_info = read.csv(paste0(wd, "LEM text - Stakeholders.csv"))
A = jsonlite::read_json(paste0(wd, mapid, ".json"))
reps = jsonlite::read_json(paste0(wd, mapid, "_reps.json"))
sub_result = readRDS(paste0(wd, mapid, "a_sub_result_new.rds")) #record satisfy level
submission_name = c()
sub_approval_count = c()
for (i in 1:length(sub_result)){
  submission_name = append(submission_name, sub_result[[i]]$userKey)
  sub_approval_count = append(sub_approval_count, sub_result[[i]]$approvalCount)
}
sub_approval_count = sub_approval_count/9
# sub_approval_count
sh_name = A_matrix %>%
  select(c(Name)) %>%
  unique() %>%
  pull()
sh_info = sh_info %>% 
  filter(Name %in% sh_name) %>% 
  arrange(match(Name, sh_name)) %>% 
  unite("SHinfo", Name:Direction, remove = TRUE) %>% 
  pull()

reference: luc_0 = “Commercial” luc_1 = “Conservation” luc_2 = “Cropland” luc_3 = “Industrial” luc_4 = “Limited Use” luc_5 = “Pasture” luc_6 = “Recreation” luc_7 = “Residential HD” luc_8 = “Residential LD” luc_9 = “Timber” luc_10 = “Wetlands”

luc_vec = c(“luc_0”, “luc_1”,“luc_2”,“luc_3”,“luc_4”,“luc_5”,“luc_6”,“luc_7”,“luc_8”,“luc_9”,“luc_10”) luc_original = c(“20”, “31”, “50”, “21”, “30”, “60”, “22”, “23”, “24”, “40”, “10”)

1. combine conservation and limited use and set self-connection to zero

which means luc_1_X + luc_4_X, luc_X_1 + luc_X_4

A_matrix_2 <- A_matrix
B_matrix_2 <- B_matrix
C_matrix_2 <- C_matrix
for (i in 1:11) {
  A_luc1x = which(names(A_matrix_2)==paste0("luc_", 1, "_", i-1))
  A_luc4x = which(names(A_matrix_2)==paste0("luc_", 4, "_", i-1))
  B_luc1x = which(names(B_matrix_2)==paste0("luc_", 1, "_", i-1))
  B_luc4x = which(names(B_matrix_2)==paste0("luc_", 4, "_", i-1))
  C_luc1x = which(names(C_matrix_2)==paste0("luc_", 1, "_", i-1))
  C_luc4x = which(names(C_matrix_2)==paste0("luc_", 4, "_", i-1))
  A_matrix_2[[A_luc1x]] <- A_matrix_2[[A_luc1x]] + A_matrix_2[[A_luc4x]]
  B_matrix_2[[B_luc1x]] <- B_matrix_2[[B_luc1x]] + B_matrix_2[[B_luc4x]]
  C_matrix_2[[C_luc1x]] <- C_matrix_2[[C_luc1x]] + C_matrix_2[[C_luc4x]]
}
for (i in 1:11) {
  A_lucx1 = which(names(A_matrix_2)==paste0("luc_", i-1, "_", 1))
  A_lucx4 = which(names(A_matrix_2)==paste0("luc_", i-1, "_", 4))
  B_lucx1 = which(names(B_matrix_2)==paste0("luc_", i-1, "_", 1))
  B_lucx4 = which(names(B_matrix_2)==paste0("luc_", i-1, "_", 4))
  C_lucx1 = which(names(C_matrix_2)==paste0("luc_", i-1, "_", 1))
  C_lucx4 = which(names(C_matrix_2)==paste0("luc_", i-1, "_", 4))
  A_matrix_2[[A_lucx1]] <- A_matrix_2[[A_lucx1]] + A_matrix_2[[A_lucx4]]
  B_matrix_2[[B_lucx1]] <- B_matrix_2[[B_lucx1]] + B_matrix_2[[B_lucx4]]
  C_matrix_2[[C_lucx1]] <- C_matrix_2[[C_lucx1]] + C_matrix_2[[C_lucx4]]
}
for (i in 1:11) {
  A_lucxx = which(names(A_matrix_2)==paste0("luc_", i-1, "_", i-1))
  B_lucxx = which(names(B_matrix_2)==paste0("luc_", i-1, "_", i-1))
  C_lucxx = which(names(C_matrix_2)==paste0("luc_", i-1, "_", i-1))
  A_matrix_2[[A_lucxx]] = 0
  B_matrix_2[[B_lucxx]] = 0
  C_matrix_2[[C_lucxx]] = 0
}

A_matrix_2 <- A_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))
B_matrix_2 <- B_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))
C_matrix_2 <- C_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))

2. make ABC col names consistent for the ease of later work

colnames(A_matrix_2)[2] = "SH"
A_matrix_2 <- A_matrix_2 %>%
  select(-c(...1)) %>% 
  add_column(user_name = "NA", .before = "luc_0_0") %>%
  add_column(submission = "NA",.before = "luc_0_0") %>%
  add_column(index = 1:nrow(A_matrix), .before = "SH")
colnames(B_matrix_2)[2] = "SH"
B_matrix_2 <- B_matrix_2 %>%
  select(-c(...1)) %>% 
  add_column(user_name = "NA", .before = "luc_0_0") %>%
  add_column(submission = "NA",.before = "luc_0_0") %>%
  add_column(index = 1:nrow(B_matrix), .before = "SH")
C_matrix_2 <- C_matrix_2 %>%
  add_column(index = 1:nrow(C_matrix_2), .before = "user_name") %>%
  add_column(Name = "NA", .before = "user_name") %>%
  add_column(Satisfy = "NA",.before = "user_name") %>%
  add_column(N = "NA", .before = "user_name")

3.run ONA

call generate.ona.object function

generate.ona.object <- function(data, unit.col, meta.col, codes){
  output <- list()
  f.units <- unit.col
  ENA_UNIT <- rENA::merge_columns_c(f.units, cols = colnames(f.units));
  # ENA_UNIT <-  f.units
  f.raw <- data
  f.codes <- codes
  dena_data = directedENA:::ena.set.directed(f.raw, f.units, NA, f.codes)
  output.meta.data <- meta.col
  dena_data$meta.data <- data.table::as.data.table(cbind(ENA_UNIT, output.meta.data))
  for( i in colnames(dena_data$meta.data) ) {
    set(dena_data$meta.data, j = i, value = rENA::as.ena.metadata(dena_data$meta.data[[i]]))
  }
  code_length <- length(dena_data$rotation$codes);
  dena_data$rotation$adjacency.key <- data.table::data.table(matrix(c(
    rep(1:code_length, code_length),
    rep(1:code_length, each = code_length)),
    byrow = TRUE, nrow = 2
  ))
  directed.adjacency.vectors <- as.ena.matrix(data.table::as.data.table(data[, grep("V", colnames(data))]), "ena.connections")
  # aren't these two the same thing 
  dena_data$connection.counts <- data.table::as.data.table(cbind(dena_data$meta.data, directed.adjacency.vectors))
  dena_data$connection.counts = rENA::as.ena.matrix(x = dena_data$connection.counts, "ena.connections")
  for (i in which(!rENA::find_meta_cols(dena_data$connection.counts)))
    set(dena_data$connection.counts, j = i, value = as.ena.co.occurrence(as.double(dena_data$connection.counts[[i]])))
  dena_data$model$row.connection.counts = data.table::as.data.table(cbind(dena_data$meta.data, directed.adjacency.vectors))
  dena_data$model$row.connection.counts <- rENA::as.ena.matrix(dena_data$model$row.connection.counts, "row.connections")
  output = dena_data;
  return(output)
}
# 1. prepare df

# df <- A_matrix
# df <- B_matrix
df <- C_matrix_2

names(df)[7:106] <- paste0("V",seq(1:100))
df$mapid = mapid

# 2. accum
accumC <- generate.ona.object(
  df,
  unit.col = df[,1:7],
  meta.col = df[,1:7],
  codes = as.vector(
    c("Commercial",
    "Conservation_lu",
    # "Conservation",
    "Cropland",
    "Industrial",
    # "Limited Use",
    "Pasture",
    "Recreation",
    "Residential HD",
    "Residential LD",
    "Timber",
    "Wetlands")))

# 3. model
setC <- model(accumC)

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution
# 4. GoF
correlations(setC)
NA
# 1. prepare df

df1 <- A_matrix_2
# df <- B_matrix
# df <- C_matrix

names(df1)[7:106] <- paste0("V",seq(1:100))
df1$mapid = mapid

# 2. accum
accumA <- generate.ona.object(
  df1,
  unit.col = df1[,1:7],
  meta.col = df1[,1:7],
  codes = as.vector(
    c("Commercial",
    "Conservation_lu",
    # "Conservation",
    "Cropland",
    "Industrial",
    # "Limited Use",
    "Pasture",
    "Recreation",
    "Residential HD",
    "Residential LD",
    "Timber",
    "Wetlands")))

# 3. model
setA <- model(accumA)

# 4. GoF
correlations(setA)

4. project C points into A space

To do so, I need to make a set using C’s accumulation and A’s rotation matrix

set=model(accumC, rotation.set = setA$rotation)

5. ona plotting

5.1 setting global visual parameters here so that all ONA plots we generate are on the same scale

node_size_multiplier = 0.2
node_position_multiplier = 1.0
edge_size_multiplier = 0.2
point_position_multiplier = 1.0
edge_arrow_saturation_multiplier = 1.0
ona:::plot.ena.directed.set(setC) %>% 
  units( 
    points = setC$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE)

5.2 quick check points ARE being rotated

ona:::plot.ena.directed.set(setA, title = "space used for projection and its points") %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = TRUE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 

ona:::plot.ena.directed.set(setC, title = "points need to be projected in its original space") %>%
  units( 
    points = setC$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE)%>%
 nodes(
    node_size_multiplier = 0.001) 

ona:::plot.ena.directed.set(set, title = "projected points in its new space") %>%
  units(
    points = set$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE) %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 

Cluster Check:

ona:::plot.ena.directed.set(setA, title = "space used for projection and its points") %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = TRUE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 
A = setA$points[ENA_DIRECTION== 'response']

5.3 YES 9 means + submission trajectory

user_names <- unique(C_matrix$user_name)
n <- length(user_names)
qual_col_pals = brewer.pal.info[brewer.pal.info$category == 'qual',]
col_vector = unlist(mapply(brewer.pal, qual_col_pals$maxcolors, rownames(qual_col_pals)))
colors_selected <- sample(col_vector, n)
pie(rep(1,n), col=colors_selected)

colors <- c("green", "blue", "brown", "purple", "yellow", "deeppink", "Tan", "Cyan", "orange")

p <- ona:::plot.ena.directed.set(set) %>%
  units(
    points = set$points,
    points_color = "white",
    point_position_multiplier = point_position_multiplier,
    show_mean = FALSE,
    show_points = TRUE,
    with_ci = FALSE
  )

for (i in 1:length(sh_name)) {
  p <- p %>%
    units(
      points = setA$points[SH == sh_name[i] & Satisfy == "Yes"],
      points_color = colors[i],
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE,
      show_points = FALSE,
      with_ci = FALSE,
    )
}
j = 0
k = 1
prev = ""
for (i in 1:length(submission_name)) {
  if (submission_name[i] != prev) {
    j <- j+1
    prev <- submission_name[i]
    k <- 1
  }
  p <- p %>%
    add_annotations(
      x = set$points[ENA_DIRECTION == "response"]$SVD1[i],
      y = set$points[ENA_DIRECTION == "response"]$SVD2[i],
      text = paste0(submission_name[i], k),
      font = list(color = colors_selected[j]),
      showarrow = FALSE
    )
  k <- k+1
}
data.frame(Stakeholders = sh_name, Colors = colors)
p
LS0tDQp0aXRsZTogIk9OQSBhbmFseXNpcyBmb3IgaVBsYW4iDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0gDQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpIA0KYGBgDQoNCmBgYHtyfQ0Kcm0obGlzdCA9IGxzKCkpDQpsaWJyYXJ5KCJyc3R1ZGlvYXBpIikNCnNldHdkKGRpcm5hbWUoZ2V0QWN0aXZlRG9jdW1lbnRDb250ZXh0KCkkcGF0aCkpDQpgYGANCg0KVW5jb21tZW50IGFuZCBydW4gdGhpcyBibG9jayBpZiB5b3UgaGF2ZW4ndCBoYWQgdGhlc2UgcGFja2FnZXMgaW5zdGFsbGVkDQpgYGB7cn0NCiMgaW5zdGFsbC5wYWNrYWdlcygib25hIiwgcmVwb3MgPSBjKCJodHRwczovL2VwaXN0ZW1pYy1hbmFseXRpY3MuZ2l0bGFiLmlvL3FlLXBhY2thZ2VzL29uYS9jcmFuLyIsICJodHRwczovL2NyYW4ucnN0dWRpby5vcmciKSkNCiMgaW5zdGFsbC5wYWNrYWdlcygidG1hIiwgcmVwb3MgPSBjKCJodHRwczovL2VwaXN0ZW1pYy1hbmFseXRpY3MuZ2l0bGFiLmlvL3FlLXBhY2thZ2VzL3RtYS9jcmFuLyIsICJodHRwczovL2NyYW4ucnN0dWRpby5vcmciKSkNCiMgaW5zdGFsbC5wYWNrYWdlcygibWFncml0dHIiKQ0KYGBgDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KG9uYSkNCmxpYnJhcnkodG1hKQ0KbGlicmFyeShtYWdyaXR0cikNCmxpYnJhcnkockVOQSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShnZ3JlcGVsKQ0KbGlicmFyeShnZ2ZvcnRpZnkpDQpsaWJyYXJ5KGRhdGEudGFibGUpDQpsaWJyYXJ5KHN1cGVyaGVhdCkNCmxpYnJhcnkocmpzb24pDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KYGBgDQoNCiMgMC4gc2V0dGluZyB1cCBjb25zdGFudCB2YXJpYWJsZXMgKGNoYW5nZSBhcyBhcHByb3ByaWF0ZSkNCmBgYHtyfQ0KbWFwaWQgPSAiNTc3MTg3ODkiDQp3ZCA9IHBhc3RlMChnZXR3ZCgpLCAiL2RhdGEvIikNCmBgYA0KDQojIDAuIHJlYWQgQSBCIEMgbWF0cmljZXMgYW5kIG90aGVyIHJlbGV2YW50IGRhdGENCmBgYHtyfQ0KQV9tYXRyaXggPSByZWFkX2NzdihwYXN0ZTAod2QsIG1hcGlkLCAiX2FfbWF0cml4LmNzdiIpKQ0KQl9tYXRyaXggPSByZWFkX2NzdihwYXN0ZTAod2QsIG1hcGlkLCAiX2JfbWF0cml4LmNzdiIpKQ0KQ19tYXRyaXggPSByZWFkLmNzdihwYXN0ZTAod2QsIG1hcGlkLCAiX2NfbWF0cml4LmNzdiIpKQ0Kc2hfaW5mbyA9IHJlYWQuY3N2KHBhc3RlMCh3ZCwgIkxFTSB0ZXh0IC0gU3Rha2Vob2xkZXJzLmNzdiIpKQ0KQSA9IGpzb25saXRlOjpyZWFkX2pzb24ocGFzdGUwKHdkLCBtYXBpZCwgIi5qc29uIikpDQpyZXBzID0ganNvbmxpdGU6OnJlYWRfanNvbihwYXN0ZTAod2QsIG1hcGlkLCAiX3JlcHMuanNvbiIpKQ0Kc3ViX3Jlc3VsdCA9IHJlYWRSRFMocGFzdGUwKHdkLCBtYXBpZCwgImFfc3ViX3Jlc3VsdF9uZXcucmRzIikpICNyZWNvcmQgc2F0aXNmeSBsZXZlbA0KYGBgDQoNCmBgYHtyfQ0Kc3VibWlzc2lvbl9uYW1lID0gYygpDQpzdWJfYXBwcm92YWxfY291bnQgPSBjKCkNCmZvciAoaSBpbiAxOmxlbmd0aChzdWJfcmVzdWx0KSl7DQogIHN1Ym1pc3Npb25fbmFtZSA9IGFwcGVuZChzdWJtaXNzaW9uX25hbWUsIHN1Yl9yZXN1bHRbW2ldXSR1c2VyS2V5KQ0KICBzdWJfYXBwcm92YWxfY291bnQgPSBhcHBlbmQoc3ViX2FwcHJvdmFsX2NvdW50LCBzdWJfcmVzdWx0W1tpXV0kYXBwcm92YWxDb3VudCkNCn0NCmBgYA0KDQpgYGB7cn0NCnN1Yl9hcHByb3ZhbF9jb3VudCA9IHN1Yl9hcHByb3ZhbF9jb3VudC85DQojIHN1Yl9hcHByb3ZhbF9jb3VudA0KYGBgDQoNCmBgYHtyfQ0Kc2hfbmFtZSA9IEFfbWF0cml4ICU+JQ0KICBzZWxlY3QoYyhOYW1lKSkgJT4lDQogIHVuaXF1ZSgpICU+JQ0KICBwdWxsKCkNCmBgYA0KDQpgYGB7cn0NCnNoX2luZm8gPSBzaF9pbmZvICU+JSANCiAgZmlsdGVyKE5hbWUgJWluJSBzaF9uYW1lKSAlPiUgDQogIGFycmFuZ2UobWF0Y2goTmFtZSwgc2hfbmFtZSkpICU+JSANCiAgdW5pdGUoIlNIaW5mbyIsIE5hbWU6RGlyZWN0aW9uLCByZW1vdmUgPSBUUlVFKSAlPiUgDQogIHB1bGwoKQ0KYGBgDQoNCnJlZmVyZW5jZToNCmx1Y18wID0gIkNvbW1lcmNpYWwiDQpsdWNfMSA9ICJDb25zZXJ2YXRpb24iDQpsdWNfMiA9ICJDcm9wbGFuZCIgDQpsdWNfMyA9ICJJbmR1c3RyaWFsIiANCmx1Y180ID0gIkxpbWl0ZWQgVXNlIg0KbHVjXzUgPSAiUGFzdHVyZSINCmx1Y182ID0gIlJlY3JlYXRpb24iDQpsdWNfNyA9ICJSZXNpZGVudGlhbCBIRCIgDQpsdWNfOCA9ICJSZXNpZGVudGlhbCBMRCIgDQpsdWNfOSA9ICJUaW1iZXIiIA0KbHVjXzEwID0gIldldGxhbmRzIg0KDQpsdWNfdmVjID0gYygibHVjXzAiLCAibHVjXzEiLCJsdWNfMiIsImx1Y18zIiwibHVjXzQiLCJsdWNfNSIsImx1Y182IiwibHVjXzciLCJsdWNfOCIsImx1Y185IiwibHVjXzEwIikNCmx1Y19vcmlnaW5hbCA9IGMoIjIwIiwgIjMxIiwgIjUwIiwgIjIxIiwgIjMwIiwgIjYwIiwgIjIyIiwgIjIzIiwgIjI0IiwgIjQwIiwgIjEwIikNCg0KIyAxLiBjb21iaW5lIGNvbnNlcnZhdGlvbiBhbmQgbGltaXRlZCB1c2UgYW5kIHNldCBzZWxmLWNvbm5lY3Rpb24gdG8gemVybw0Kd2hpY2ggbWVhbnMgbHVjXzFfWCArIGx1Y180X1gsIGx1Y19YXzEgKyBsdWNfWF80DQpgYGB7cn0NCkFfbWF0cml4XzIgPC0gQV9tYXRyaXgNCkJfbWF0cml4XzIgPC0gQl9tYXRyaXgNCkNfbWF0cml4XzIgPC0gQ19tYXRyaXgNCmZvciAoaSBpbiAxOjExKSB7DQogIEFfbHVjMXggPSB3aGljaChuYW1lcyhBX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgMSwgIl8iLCBpLTEpKQ0KICBBX2x1YzR4ID0gd2hpY2gobmFtZXMoQV9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIDQsICJfIiwgaS0xKSkNCiAgQl9sdWMxeCA9IHdoaWNoKG5hbWVzKEJfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCAxLCAiXyIsIGktMSkpDQogIEJfbHVjNHggPSB3aGljaChuYW1lcyhCX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgNCwgIl8iLCBpLTEpKQ0KICBDX2x1YzF4ID0gd2hpY2gobmFtZXMoQ19tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIDEsICJfIiwgaS0xKSkNCiAgQ19sdWM0eCA9IHdoaWNoKG5hbWVzKENfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCA0LCAiXyIsIGktMSkpDQogIEFfbWF0cml4XzJbW0FfbHVjMXhdXSA8LSBBX21hdHJpeF8yW1tBX2x1YzF4XV0gKyBBX21hdHJpeF8yW1tBX2x1YzR4XV0NCiAgQl9tYXRyaXhfMltbQl9sdWMxeF1dIDwtIEJfbWF0cml4XzJbW0JfbHVjMXhdXSArIEJfbWF0cml4XzJbW0JfbHVjNHhdXQ0KICBDX21hdHJpeF8yW1tDX2x1YzF4XV0gPC0gQ19tYXRyaXhfMltbQ19sdWMxeF1dICsgQ19tYXRyaXhfMltbQ19sdWM0eF1dDQp9DQpmb3IgKGkgaW4gMToxMSkgew0KICBBX2x1Y3gxID0gd2hpY2gobmFtZXMoQV9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIGktMSwgIl8iLCAxKSkNCiAgQV9sdWN4NCA9IHdoaWNoKG5hbWVzKEFfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgNCkpDQogIEJfbHVjeDEgPSB3aGljaChuYW1lcyhCX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIDEpKQ0KICBCX2x1Y3g0ID0gd2hpY2gobmFtZXMoQl9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIGktMSwgIl8iLCA0KSkNCiAgQ19sdWN4MSA9IHdoaWNoKG5hbWVzKENfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgMSkpDQogIENfbHVjeDQgPSB3aGljaChuYW1lcyhDX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIDQpKQ0KICBBX21hdHJpeF8yW1tBX2x1Y3gxXV0gPC0gQV9tYXRyaXhfMltbQV9sdWN4MV1dICsgQV9tYXRyaXhfMltbQV9sdWN4NF1dDQogIEJfbWF0cml4XzJbW0JfbHVjeDFdXSA8LSBCX21hdHJpeF8yW1tCX2x1Y3gxXV0gKyBCX21hdHJpeF8yW1tCX2x1Y3g0XV0NCiAgQ19tYXRyaXhfMltbQ19sdWN4MV1dIDwtIENfbWF0cml4XzJbW0NfbHVjeDFdXSArIENfbWF0cml4XzJbW0NfbHVjeDRdXQ0KfQ0KZm9yIChpIGluIDE6MTEpIHsNCiAgQV9sdWN4eCA9IHdoaWNoKG5hbWVzKEFfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgaS0xKSkNCiAgQl9sdWN4eCA9IHdoaWNoKG5hbWVzKEJfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgaS0xKSkNCiAgQ19sdWN4eCA9IHdoaWNoKG5hbWVzKENfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgaS0xKSkNCiAgQV9tYXRyaXhfMltbQV9sdWN4eF1dID0gMA0KICBCX21hdHJpeF8yW1tCX2x1Y3h4XV0gPSAwDQogIENfbWF0cml4XzJbW0NfbHVjeHhdXSA9IDANCn0NCg0KQV9tYXRyaXhfMiA8LSBBX21hdHJpeF8yICU+JSBzZWxlY3QoLWMobHVjXzRfMCwgbHVjXzRfMSwgbHVjXzRfMiwgbHVjXzRfMywgbHVjXzRfNCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzRfNSwgbHVjXzRfNiwgbHVjXzRfNywgbHVjXzRfOCwgbHVjXzRfOSwgbHVjXzRfMTAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzBfNCwgbHVjXzFfNCwgbHVjXzJfNCwgbHVjXzNfNCwgbHVjXzRfNCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfNV80LCBsdWNfNl80LCBsdWNfN180LCBsdWNfOF80LCBsdWNfOV80LCBsdWNfMTBfNCkpDQpCX21hdHJpeF8yIDwtIEJfbWF0cml4XzIgJT4lIHNlbGVjdCgtYyhsdWNfNF8wLCBsdWNfNF8xLCBsdWNfNF8yLCBsdWNfNF8zLCBsdWNfNF80LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfNF81LCBsdWNfNF82LCBsdWNfNF83LCBsdWNfNF84LCBsdWNfNF85LCBsdWNfNF8xMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfMF80LCBsdWNfMV80LCBsdWNfMl80LCBsdWNfM180LCBsdWNfNF80LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y181XzQsIGx1Y182XzQsIGx1Y183XzQsIGx1Y184XzQsIGx1Y185XzQsIGx1Y18xMF80KSkNCkNfbWF0cml4XzIgPC0gQ19tYXRyaXhfMiAlPiUgc2VsZWN0KC1jKGx1Y180XzAsIGx1Y180XzEsIGx1Y180XzIsIGx1Y180XzMsIGx1Y180XzQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y180XzUsIGx1Y180XzYsIGx1Y180XzcsIGx1Y180XzgsIGx1Y180XzksIGx1Y180XzEwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y18wXzQsIGx1Y18xXzQsIGx1Y18yXzQsIGx1Y18zXzQsIGx1Y180XzQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzVfNCwgbHVjXzZfNCwgbHVjXzdfNCwgbHVjXzhfNCwgbHVjXzlfNCwgbHVjXzEwXzQpKQ0KYGBgDQoNCiMgMi4gbWFrZSBBQkMgY29sIG5hbWVzIGNvbnNpc3RlbnQgZm9yIHRoZSBlYXNlIG9mIGxhdGVyIHdvcmsNCmBgYHtyfQ0KY29sbmFtZXMoQV9tYXRyaXhfMilbMl0gPSAiU0giDQpBX21hdHJpeF8yIDwtIEFfbWF0cml4XzIgJT4lDQogIHNlbGVjdCgtYyguLi4xKSkgJT4lIA0KICBhZGRfY29sdW1uKHVzZXJfbmFtZSA9ICJOQSIsIC5iZWZvcmUgPSAibHVjXzBfMCIpICU+JQ0KICBhZGRfY29sdW1uKHN1Ym1pc3Npb24gPSAiTkEiLC5iZWZvcmUgPSAibHVjXzBfMCIpICU+JQ0KICBhZGRfY29sdW1uKGluZGV4ID0gMTpucm93KEFfbWF0cml4KSwgLmJlZm9yZSA9ICJTSCIpDQpgYGANCg0KYGBge3J9DQpjb2xuYW1lcyhCX21hdHJpeF8yKVsyXSA9ICJTSCINCkJfbWF0cml4XzIgPC0gQl9tYXRyaXhfMiAlPiUNCiAgc2VsZWN0KC1jKC4uLjEpKSAlPiUgDQogIGFkZF9jb2x1bW4odXNlcl9uYW1lID0gIk5BIiwgLmJlZm9yZSA9ICJsdWNfMF8wIikgJT4lDQogIGFkZF9jb2x1bW4oc3VibWlzc2lvbiA9ICJOQSIsLmJlZm9yZSA9ICJsdWNfMF8wIikgJT4lDQogIGFkZF9jb2x1bW4oaW5kZXggPSAxOm5yb3coQl9tYXRyaXgpLCAuYmVmb3JlID0gIlNIIikNCmBgYA0KDQpgYGB7cn0NCkNfbWF0cml4XzIgPC0gQ19tYXRyaXhfMiAlPiUNCiAgYWRkX2NvbHVtbihpbmRleCA9IDE6bnJvdyhDX21hdHJpeF8yKSwgLmJlZm9yZSA9ICJ1c2VyX25hbWUiKSAlPiUNCiAgYWRkX2NvbHVtbihOYW1lID0gIk5BIiwgLmJlZm9yZSA9ICJ1c2VyX25hbWUiKSAlPiUNCiAgYWRkX2NvbHVtbihTYXRpc2Z5ID0gIk5BIiwuYmVmb3JlID0gInVzZXJfbmFtZSIpICU+JQ0KICBhZGRfY29sdW1uKE4gPSAiTkEiLCAuYmVmb3JlID0gInVzZXJfbmFtZSIpDQpgYGANCg0KIyAzLnJ1biBPTkENCmNhbGwgZ2VuZXJhdGUub25hLm9iamVjdCBmdW5jdGlvbg0KYGBge3IgZ2VuZXJhdGUub25hLm9iamVjdH0NCmdlbmVyYXRlLm9uYS5vYmplY3QgPC0gZnVuY3Rpb24oZGF0YSwgdW5pdC5jb2wsIG1ldGEuY29sLCBjb2Rlcyl7DQogIG91dHB1dCA8LSBsaXN0KCkNCiAgZi51bml0cyA8LSB1bml0LmNvbA0KICBFTkFfVU5JVCA8LSByRU5BOjptZXJnZV9jb2x1bW5zX2MoZi51bml0cywgY29scyA9IGNvbG5hbWVzKGYudW5pdHMpKTsNCiAgIyBFTkFfVU5JVCA8LSAgZi51bml0cw0KICBmLnJhdyA8LSBkYXRhDQogIGYuY29kZXMgPC0gY29kZXMNCiAgZGVuYV9kYXRhID0gZGlyZWN0ZWRFTkE6OjplbmEuc2V0LmRpcmVjdGVkKGYucmF3LCBmLnVuaXRzLCBOQSwgZi5jb2RlcykNCiAgb3V0cHV0Lm1ldGEuZGF0YSA8LSBtZXRhLmNvbA0KICBkZW5hX2RhdGEkbWV0YS5kYXRhIDwtIGRhdGEudGFibGU6OmFzLmRhdGEudGFibGUoY2JpbmQoRU5BX1VOSVQsIG91dHB1dC5tZXRhLmRhdGEpKQ0KICBmb3IoIGkgaW4gY29sbmFtZXMoZGVuYV9kYXRhJG1ldGEuZGF0YSkgKSB7DQogICAgc2V0KGRlbmFfZGF0YSRtZXRhLmRhdGEsIGogPSBpLCB2YWx1ZSA9IHJFTkE6OmFzLmVuYS5tZXRhZGF0YShkZW5hX2RhdGEkbWV0YS5kYXRhW1tpXV0pKQ0KICB9DQogIGNvZGVfbGVuZ3RoIDwtIGxlbmd0aChkZW5hX2RhdGEkcm90YXRpb24kY29kZXMpOw0KICBkZW5hX2RhdGEkcm90YXRpb24kYWRqYWNlbmN5LmtleSA8LSBkYXRhLnRhYmxlOjpkYXRhLnRhYmxlKG1hdHJpeChjKA0KICAgIHJlcCgxOmNvZGVfbGVuZ3RoLCBjb2RlX2xlbmd0aCksDQogICAgcmVwKDE6Y29kZV9sZW5ndGgsIGVhY2ggPSBjb2RlX2xlbmd0aCkpLA0KICAgIGJ5cm93ID0gVFJVRSwgbnJvdyA9IDINCiAgKSkNCiAgZGlyZWN0ZWQuYWRqYWNlbmN5LnZlY3RvcnMgPC0gYXMuZW5hLm1hdHJpeChkYXRhLnRhYmxlOjphcy5kYXRhLnRhYmxlKGRhdGFbLCBncmVwKCJWIiwgY29sbmFtZXMoZGF0YSkpXSksICJlbmEuY29ubmVjdGlvbnMiKQ0KICAjIGFyZW4ndCB0aGVzZSB0d28gdGhlIHNhbWUgdGhpbmcgDQogIGRlbmFfZGF0YSRjb25uZWN0aW9uLmNvdW50cyA8LSBkYXRhLnRhYmxlOjphcy5kYXRhLnRhYmxlKGNiaW5kKGRlbmFfZGF0YSRtZXRhLmRhdGEsIGRpcmVjdGVkLmFkamFjZW5jeS52ZWN0b3JzKSkNCiAgZGVuYV9kYXRhJGNvbm5lY3Rpb24uY291bnRzID0gckVOQTo6YXMuZW5hLm1hdHJpeCh4ID0gZGVuYV9kYXRhJGNvbm5lY3Rpb24uY291bnRzLCAiZW5hLmNvbm5lY3Rpb25zIikNCiAgZm9yIChpIGluIHdoaWNoKCFyRU5BOjpmaW5kX21ldGFfY29scyhkZW5hX2RhdGEkY29ubmVjdGlvbi5jb3VudHMpKSkNCiAgICBzZXQoZGVuYV9kYXRhJGNvbm5lY3Rpb24uY291bnRzLCBqID0gaSwgdmFsdWUgPSBhcy5lbmEuY28ub2NjdXJyZW5jZShhcy5kb3VibGUoZGVuYV9kYXRhJGNvbm5lY3Rpb24uY291bnRzW1tpXV0pKSkNCiAgZGVuYV9kYXRhJG1vZGVsJHJvdy5jb25uZWN0aW9uLmNvdW50cyA9IGRhdGEudGFibGU6OmFzLmRhdGEudGFibGUoY2JpbmQoZGVuYV9kYXRhJG1ldGEuZGF0YSwgZGlyZWN0ZWQuYWRqYWNlbmN5LnZlY3RvcnMpKQ0KICBkZW5hX2RhdGEkbW9kZWwkcm93LmNvbm5lY3Rpb24uY291bnRzIDwtIHJFTkE6OmFzLmVuYS5tYXRyaXgoZGVuYV9kYXRhJG1vZGVsJHJvdy5jb25uZWN0aW9uLmNvdW50cywgInJvdy5jb25uZWN0aW9ucyIpDQogIG91dHB1dCA9IGRlbmFfZGF0YTsNCiAgcmV0dXJuKG91dHB1dCkNCn0NCmBgYA0KDQpgYGB7cn0NCiMgMS4gcHJlcGFyZSBkZg0KDQojIGRmIDwtIEFfbWF0cml4DQojIGRmIDwtIEJfbWF0cml4DQpkZiA8LSBDX21hdHJpeF8yDQoNCm5hbWVzKGRmKVs3OjEwNl0gPC0gcGFzdGUwKCJWIixzZXEoMToxMDApKQ0KZGYkbWFwaWQgPSBtYXBpZA0KDQojIDIuIGFjY3VtDQphY2N1bUMgPC0gZ2VuZXJhdGUub25hLm9iamVjdCgNCiAgZGYsDQogIHVuaXQuY29sID0gZGZbLDE6N10sDQogIG1ldGEuY29sID0gZGZbLDE6N10sDQogIGNvZGVzID0gYXMudmVjdG9yKA0KICAgIGMoIkNvbW1lcmNpYWwiLA0KICAgICJDb25zZXJ2YXRpb25fbHUiLA0KICAgICMgIkNvbnNlcnZhdGlvbiIsDQogICAgIkNyb3BsYW5kIiwNCiAgICAiSW5kdXN0cmlhbCIsDQogICAgIyAiTGltaXRlZCBVc2UiLA0KICAgICJQYXN0dXJlIiwNCiAgICAiUmVjcmVhdGlvbiIsDQogICAgIlJlc2lkZW50aWFsIEhEIiwNCiAgICAiUmVzaWRlbnRpYWwgTEQiLA0KICAgICJUaW1iZXIiLA0KICAgICJXZXRsYW5kcyIpKSkNCg0KIyAzLiBtb2RlbA0Kc2V0QyA8LSBtb2RlbChhY2N1bUMpDQoNCiMgNC4gR29GDQpjb3JyZWxhdGlvbnMoc2V0QykNCg0KYGBgDQoNCmBgYHtyfQ0KIyAxLiBwcmVwYXJlIGRmDQoNCmRmMSA8LSBBX21hdHJpeF8yDQojIGRmIDwtIEJfbWF0cml4DQojIGRmIDwtIENfbWF0cml4DQoNCm5hbWVzKGRmMSlbNzoxMDZdIDwtIHBhc3RlMCgiViIsc2VxKDE6MTAwKSkNCmRmMSRtYXBpZCA9IG1hcGlkDQoNCiMgMi4gYWNjdW0NCmFjY3VtQSA8LSBnZW5lcmF0ZS5vbmEub2JqZWN0KA0KICBkZjEsDQogIHVuaXQuY29sID0gZGYxWywxOjddLA0KICBtZXRhLmNvbCA9IGRmMVssMTo3XSwNCiAgY29kZXMgPSBhcy52ZWN0b3IoDQogICAgYygiQ29tbWVyY2lhbCIsDQogICAgIkNvbnNlcnZhdGlvbl9sdSIsDQogICAgIyAiQ29uc2VydmF0aW9uIiwNCiAgICAiQ3JvcGxhbmQiLA0KICAgICJJbmR1c3RyaWFsIiwNCiAgICAjICJMaW1pdGVkIFVzZSIsDQogICAgIlBhc3R1cmUiLA0KICAgICJSZWNyZWF0aW9uIiwNCiAgICAiUmVzaWRlbnRpYWwgSEQiLA0KICAgICJSZXNpZGVudGlhbCBMRCIsDQogICAgIlRpbWJlciIsDQogICAgIldldGxhbmRzIikpKQ0KDQojIDMuIG1vZGVsDQpzZXRBIDwtIG1vZGVsKGFjY3VtQSkNCg0KIyA0LiBHb0YNCmNvcnJlbGF0aW9ucyhzZXRBKQ0KYGBgDQoNCiMgNC4gcHJvamVjdCBDIHBvaW50cyBpbnRvIEEgc3BhY2UNClRvIGRvIHNvLCBJIG5lZWQgdG8gbWFrZSBhIHNldCB1c2luZyBDJ3MgYWNjdW11bGF0aW9uIGFuZCBBJ3Mgcm90YXRpb24gbWF0cml4DQpgYGB7cn0NCnNldD1tb2RlbChhY2N1bUMsIHJvdGF0aW9uLnNldCA9IHNldEEkcm90YXRpb24pDQpgYGANCg0KIyA1LiBvbmEgcGxvdHRpbmcgDQojIyA1LjEgc2V0dGluZyBnbG9iYWwgdmlzdWFsIHBhcmFtZXRlcnMgaGVyZSBzbyB0aGF0IGFsbCBPTkEgcGxvdHMgd2UgZ2VuZXJhdGUgYXJlIG9uIHRoZSBzYW1lIHNjYWxlDQpgYGB7cn0NCm5vZGVfc2l6ZV9tdWx0aXBsaWVyID0gMC4yDQpub2RlX3Bvc2l0aW9uX211bHRpcGxpZXIgPSAxLjANCmVkZ2Vfc2l6ZV9tdWx0aXBsaWVyID0gMC4yDQpwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyID0gMS4wDQplZGdlX2Fycm93X3NhdHVyYXRpb25fbXVsdGlwbGllciA9IDEuMA0KYGBgDQoNCmBgYHtyfQ0Kb25hOjo6cGxvdC5lbmEuZGlyZWN0ZWQuc2V0KHNldEMpICU+JSANCiAgdW5pdHMoIA0KICAgIHBvaW50cyA9IHNldEMkcG9pbnRzLA0KICAgIHBvaW50c19jb2xvciA9ICJibGFjayIsDQogICAgc2hvd19tZWFuID0gRkFMU0UsIHNob3dfcG9pbnRzID0gVFJVRSwgd2l0aF9jaSA9IEZBTFNFKQ0KYGBgDQoNCiMjIDUuMiBxdWljayBjaGVjayBwb2ludHMgQVJFIGJlaW5nIHJvdGF0ZWQNCmBgYHtyfQ0Kb25hOjo6cGxvdC5lbmEuZGlyZWN0ZWQuc2V0KHNldEEsIHRpdGxlID0gInNwYWNlIHVzZWQgZm9yIHByb2plY3Rpb24gYW5kIGl0cyBwb2ludHMiKSAlPiUNCiAgdW5pdHMoDQogICAgcG9pbnRzID0gc2V0QSRwb2ludHMsDQogICAgcG9pbnRzX2NvbG9yID0gImdyYXkiLA0KICAgIHNob3dfbWVhbiA9IFRSVUUsIHNob3dfcG9pbnRzID0gVFJVRSwgd2l0aF9jaSA9IEZBTFNFKSAlPiUNCiBub2RlcygNCiAgICBub2RlX3NpemVfbXVsdGlwbGllciA9IDAuMDAxKSANCg0Kb25hOjo6cGxvdC5lbmEuZGlyZWN0ZWQuc2V0KHNldEMsIHRpdGxlID0gInBvaW50cyBuZWVkIHRvIGJlIHByb2plY3RlZCBpbiBpdHMgb3JpZ2luYWwgc3BhY2UiKSAlPiUNCiAgdW5pdHMoIA0KICAgIHBvaW50cyA9IHNldEMkcG9pbnRzLA0KICAgIHBvaW50c19jb2xvciA9ICJibGFjayIsDQogICAgc2hvd19tZWFuID0gRkFMU0UsIHNob3dfcG9pbnRzID0gVFJVRSwgd2l0aF9jaSA9IEZBTFNFKSU+JQ0KIG5vZGVzKA0KICAgIG5vZGVfc2l6ZV9tdWx0aXBsaWVyID0gMC4wMDEpIA0KDQpvbmE6OjpwbG90LmVuYS5kaXJlY3RlZC5zZXQoc2V0LCB0aXRsZSA9ICJwcm9qZWN0ZWQgcG9pbnRzIGluIGl0cyBuZXcgc3BhY2UiKSAlPiUNCiAgdW5pdHMoDQogICAgcG9pbnRzID0gc2V0JHBvaW50cywNCiAgICBwb2ludHNfY29sb3IgPSAiYmxhY2siLA0KICAgIHNob3dfbWVhbiA9IEZBTFNFLCBzaG93X3BvaW50cyA9IFRSVUUsIHdpdGhfY2kgPSBGQUxTRSkgJT4lDQogIHVuaXRzKA0KICAgIHBvaW50cyA9IHNldEEkcG9pbnRzLA0KICAgIHBvaW50c19jb2xvciA9ICJncmF5IiwNCiAgICBzaG93X21lYW4gPSBGQUxTRSwgc2hvd19wb2ludHMgPSBUUlVFLCB3aXRoX2NpID0gRkFMU0UpICU+JQ0KIG5vZGVzKA0KICAgIG5vZGVfc2l6ZV9tdWx0aXBsaWVyID0gMC4wMDEpIA0KYGBgDQoNCiMjIENsdXN0ZXIgQ2hlY2s6DQoNCg0KYGBge3J9DQpvbmE6OjpwbG90LmVuYS5kaXJlY3RlZC5zZXQoc2V0QSwgdGl0bGUgPSAic3BhY2UgdXNlZCBmb3IgcHJvamVjdGlvbiBhbmQgaXRzIHBvaW50cyIpICU+JQ0KICB1bml0cygNCiAgICBwb2ludHMgPSBzZXRBJHBvaW50cywNCiAgICBwb2ludHNfY29sb3IgPSAiZ3JheSIsDQogICAgc2hvd19tZWFuID0gVFJVRSwgc2hvd19wb2ludHMgPSBUUlVFLCB3aXRoX2NpID0gRkFMU0UpICU+JQ0KIG5vZGVzKA0KICAgIG5vZGVfc2l6ZV9tdWx0aXBsaWVyID0gMC4wMDEpIA0KYGBgDQoNCmBgYHtyfQ0KQSA9IHNldEEkcG9pbnRzW0VOQV9ESVJFQ1RJT049PSAncmVzcG9uc2UnXQ0KYGBgDQoNCiMjIDUuMyBZRVMgOSBtZWFucyArIHN1Ym1pc3Npb24gdHJhamVjdG9yeQ0KDQpgYGB7cn0NCnVzZXJfbmFtZXMgPC0gdW5pcXVlKENfbWF0cml4JHVzZXJfbmFtZSkNCm4gPC0gbGVuZ3RoKHVzZXJfbmFtZXMpDQpxdWFsX2NvbF9wYWxzID0gYnJld2VyLnBhbC5pbmZvW2JyZXdlci5wYWwuaW5mbyRjYXRlZ29yeSA9PSAncXVhbCcsXQ0KY29sX3ZlY3RvciA9IHVubGlzdChtYXBwbHkoYnJld2VyLnBhbCwgcXVhbF9jb2xfcGFscyRtYXhjb2xvcnMsIHJvd25hbWVzKHF1YWxfY29sX3BhbHMpKSkNCmNvbG9yc19zZWxlY3RlZCA8LSBzYW1wbGUoY29sX3ZlY3RvciwgbikNCnBpZShyZXAoMSxuKSwgY29sPWNvbG9yc19zZWxlY3RlZCkNCmBgYA0KDQpgYGB7cn0NCmNvbG9ycyA8LSBjKCJncmVlbiIsICJibHVlIiwgImJyb3duIiwgInB1cnBsZSIsICJ5ZWxsb3ciLCAiZGVlcHBpbmsiLCAiVGFuIiwgIkN5YW4iLCAib3JhbmdlIikNCg0KcCA8LSBvbmE6OjpwbG90LmVuYS5kaXJlY3RlZC5zZXQoc2V0KSAlPiUNCiAgdW5pdHMoDQogICAgcG9pbnRzID0gc2V0JHBvaW50cywNCiAgICBwb2ludHNfY29sb3IgPSAid2hpdGUiLA0KICAgIHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIgPSBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyLA0KICAgIHNob3dfbWVhbiA9IEZBTFNFLA0KICAgIHNob3dfcG9pbnRzID0gVFJVRSwNCiAgICB3aXRoX2NpID0gRkFMU0UNCiAgKQ0KDQpmb3IgKGkgaW4gMTpsZW5ndGgoc2hfbmFtZSkpIHsNCiAgcCA8LSBwICU+JQ0KICAgIHVuaXRzKA0KICAgICAgcG9pbnRzID0gc2V0QSRwb2ludHNbU0ggPT0gc2hfbmFtZVtpXSAmIFNhdGlzZnkgPT0gIlllcyJdLA0KICAgICAgcG9pbnRzX2NvbG9yID0gY29sb3JzW2ldLA0KICAgICAgcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciA9IHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIsDQogICAgICBzaG93X21lYW4gPSBUUlVFLA0KICAgICAgc2hvd19wb2ludHMgPSBGQUxTRSwNCiAgICAgIHdpdGhfY2kgPSBGQUxTRSwNCiAgICApDQp9DQpqID0gMA0KayA9IDENCnByZXYgPSAiIg0KZm9yIChpIGluIDE6bGVuZ3RoKHN1Ym1pc3Npb25fbmFtZSkpIHsNCiAgaWYgKHN1Ym1pc3Npb25fbmFtZVtpXSAhPSBwcmV2KSB7DQogICAgaiA8LSBqKzENCiAgICBwcmV2IDwtIHN1Ym1pc3Npb25fbmFtZVtpXQ0KICAgIGsgPC0gMQ0KICB9DQogIHAgPC0gcCAlPiUNCiAgICBhZGRfYW5ub3RhdGlvbnMoDQogICAgICB4ID0gc2V0JHBvaW50c1tFTkFfRElSRUNUSU9OID09ICJyZXNwb25zZSJdJFNWRDFbaV0sDQogICAgICB5ID0gc2V0JHBvaW50c1tFTkFfRElSRUNUSU9OID09ICJyZXNwb25zZSJdJFNWRDJbaV0sDQogICAgICB0ZXh0ID0gcGFzdGUwKHN1Ym1pc3Npb25fbmFtZVtpXSwgayksDQogICAgICBmb250ID0gbGlzdChjb2xvciA9IGNvbG9yc19zZWxlY3RlZFtqXSksDQogICAgICBzaG93YXJyb3cgPSBGQUxTRQ0KICAgICkNCiAgayA8LSBrKzENCn0NCmRhdGEuZnJhbWUoU3Rha2Vob2xkZXJzID0gc2hfbmFtZSwgQ29sb3JzID0gY29sb3JzKQ0KcA0KYGBgDQoNCg==